#region Imported Namespaces
using System;
using System.Collections;
using System.Data;
using System.Reflection;
using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using DataAccess = PHSRAG.Utility.DataAccess;
using Forms = PHSRAG.Insight21.FormsManagement;
using PHSRAG.Insight21.FormsManagement;
using Serialization=PHSRAG.Insight21.FormsManagement.Serialization;
using System.Xml;
using System.Data.SqlClient;
using PHSRAG.Insight21.CDS;
using System.Text.RegularExpressions;
#endregion

namespace PHSRAG.Insight21.Humans
{
	/// <summary>
	/// Summary description for ProtocolVersion.
	/// </summary>
	public class ProtocolVersion : BO.SmartBusinessObject,System.ICloneable
	{
		#region Statics
		/// <summary>
		/// Key used to place and/or retrieve this object from the cache.
		/// </summary>
		public static string ProtocolVersionKey
		{
			get { return protocolVersionKey; }
		}
		#endregion

		#region Instance Variables
		private int version;
		private string status;
		private int protocolProcessId=0;
		private DateTime createDate;
		private DateTime lockDate;
		private ArrayList questionnaireAnswers;	
		#endregion

		#region Constants
		private const string protocolVersionKey = "ProtocolVersion_3B574644-A848-4f06-A601-B0B9522D4581";
		/// <summary>
		///  PP dataTable Columns
		/// </summary>
		private const string ColumnId = "Id";
		private const string ColumnVersion = "Version";
		private const string ColumnStatus = "Status";
		private const string ColumnProtocolProcessId = "ProtocolProcessId";
		private const string ColumnLockDate = "LockedDate";
		private const string ColumnCreateDate = "CreatedDate";
		#endregion

		#region Properties
		/// <summary>
		/// Get/Set the Version number of the ProtocolVersion
		/// </summary>
		public int Version
		{
			get { return version; }
			set { SetDirty( ref version, value ); }
		}

		/// <summary>
		/// Get/Set the Status of Protocol Version
		/// </summary>
		public string Status
		{
			get { return status; }
			set { SetDirty( ref status, value ); }
		}

		/// <summary>
		/// Get/Set the protocol processID this ProtocolVersion belongs to.
		/// </summary>
		public int ProtocolProcessId
		{
			get { return protocolProcessId; }
			set { SetDirty( ref protocolProcessId, value ); }
		}

		/// <summary>
		/// Get the Creation Date of the Protocol. Has no Set, since it's done 
		/// on the Insert of the protocol. 
		/// </summary>
		public DateTime CreateDate
		{
			get { return createDate; }
		}

		/// <summary>
		/// Get/Set the DateTime the PrtocolVersion was last locked.
		/// </summary>
		public DateTime LockDate
		{
			get { return lockDate; }
			set { SetDirty( ref lockDate, value ); } 
		}

		/// <summary>
		///  Get/Set the Array list of all Questionnaire Answers.
		/// </summary>
		public ArrayList QuestionnaireAnswers
		{
			get 
			{
				if ( questionnaireAnswers == null )
				{
					QuestionnaireAnswers = GetQuestionnaireAnswers(this.CachePolicy );
					
				}
				return questionnaireAnswers;
			}

			set { questionnaireAnswers = value; }
		}

		/// <summary>
		/// Cache Key uniquely identifies this object within the cache.
		/// </summary>
		/// <returns>the unique string for this object.</returns>
		public override string CacheKey()
		{
			return ProtocolVersionKey;
		}
		#endregion

		#region Constructors
		/// <summary>
		/// New Constructor.
		/// </summary>
		/// <param name="cachePolicy">the current CachePolicy</param>
		public ProtocolVersion(ICachePolicy cachePolicy) : base(cachePolicy)
		{
		}

		/// <summary>
		/// Data Row constructor
		/// </summary>
		/// <param name="cachePolicy">the current CachePolicy</param>
		/// <param name="row">Datarow to load the Version from.</param>
		public ProtocolVersion(ICachePolicy cachePolicy, DataRow row) : base(cachePolicy)
		{
			Id			= (int)row[ColumnId];
			version		= (int)row[ColumnVersion];
			status		= (string)row[ColumnStatus];
			protocolProcessId = (int)row[ColumnProtocolProcessId];
			object o	= row[ColumnCreateDate];
			createDate  = (o ==DBNull.Value) ? DateTime.MinValue : (DateTime)o;
			o			= row[ColumnLockDate];
			lockDate	= (o ==DBNull.Value) ? DateTime.MinValue : (DateTime)o;
			CachePolicy=cachePolicy;

		}
		#endregion

		#region abstract methods

		/// <summary>
		/// Delete ProtocoLVersion. Note this method is not currently implemented.
		/// Calling this method will currently throw an exception.
		/// </summary>
		/// <param name="sqlTransaction">DB Transaction to use during deletion.</param>
		protected override void DeleteObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
		{
			throw new Exception("ProtocolVersion.DeleteObject is not yet implemented.");
		}

		/// <summary>
		/// Determines if this ProtocoLVersion is Dirty and needs to be saved.
		/// </summary>
		/// <returns>True if it's dirty, false if it's not.</returns>
		public override bool IsDirty()
		{
			if( Dirty )
				return true;

			// QuestionnaireAnswers
			int questionnaireAnswerCount=this.QuestionnaireAnswers.Count;
			for( int i = 0; i < questionnaireAnswerCount; ++i)
			{
				Forms.QuestionnaireAnswer questAnswer = (Forms.QuestionnaireAnswer)this.QuestionnaireAnswers[i];

				if( questAnswer.IsDirty() )
					return true;
			}

			return false;
		}


		/// <summary>
		/// Saves this ProtocolVersion and any contained objects, if any.
		/// </summary>
		/// <param name="sqlTransaction">SQL transaction to use during the save.</param>
		protected override void SaveObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
		{
			object id = DataAccess.ExecuteScalar( sqlTransaction.Connection, sqlTransaction, "SaveProtocolVersion", 
				DataAccess.BuildSqlParameterArray(
				"@id", SqlDbType.Int, Id,
				"@status", SqlDbType.VarChar, Status,
				"@protocolProcessId", SqlDbType.Int, ProtocolProcessId,
				"@lockedDate", SqlDbType.DateTime, (LockDate == DateTime.MinValue) ? (object)DBNull.Value : (object)LockDate,
				"@version", SqlDbType.Int, Version ));

			Id = Convert.ToInt32 (id);

			if (questionnaireAnswers != null)
			{
				foreach(QuestionnaireAnswer questAnswer in questionnaireAnswers)
				{
					int questAnswerIdBeforeSave = questAnswer.Id;
					questAnswer.Save(sqlTransaction);
					if (questAnswerIdBeforeSave == 0)
					{
						Utility.DataAccess.ExecuteScalar(sqlTransaction.Connection, sqlTransaction, "SaveProtocolVersionQuestionnaireAnswerMap",
							Utility.DataAccess.BuildSqlParameterArray(
							"@protocolVersionId", SqlDbType.Int, Id
							,"@questionnaireAnswerId", SqlDbType.Int, questAnswer.Id
							));
					}
				}
			}
			
			// set the quesionnaireanswers to Null so we can reload them with their Type the next 
			// time they are accessed.
			questionnaireAnswers = null;
		}

		/// <summary>
		/// Load up a ProtocolVersion based on params passed in, from database
		/// represented by Connection string.
		/// </summary>
		/// <param name="connectionString">DB connection string.</param>
		/// <param name="args">params collection of arguments for the Load.</param>
		public override void Load(string connectionString, params object[] args)
		{
			if ( args.Length != 1 )
				throw new Exception("ProtocolVersion.Load expects ID only.");

			try
			{
				DataSet newDataSet = Utility.DataAccess.GetDataSet( connectionString, "GetProtocolVersion", 
					Utility.DataAccess.BuildSqlParameterArray("@id", SqlDbType.Int, (int)args[0]));
				
				DataTable table = newDataSet.Tables[0];
				DataRow row = table.Rows[0];

				Id			= (int)row[ColumnId];
				version		= (int)row[ColumnVersion];
				object o;
				o=row[ColumnStatus];
				status		= (o==DBNull.Value)? string.Empty:(string)row[ColumnStatus];
				protocolProcessId = (int)row[ColumnProtocolProcessId];
				o	= row[ColumnCreateDate];
				createDate  = (o ==DBNull.Value) ? DateTime.MinValue : (DateTime)o;
				o	= row[ColumnLockDate];
				lockDate	= (o ==DBNull.Value) ? DateTime.MinValue : (DateTime)o;
			}
			catch(Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog ("ProtocolProcess Load", ex, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		#endregion

		#region Public Methods
	
		/// <summary>
		/// GetCompleteQuestionnaireAnswerList returns a list of all QuestionnaireAnswers for 
		/// a given ProtocolVersion merged with all available Questionnaires. This populates the 
		/// complete Grid list on the AddDeleteForms page.
		/// </summary>
		/// <param name="protocolVersionQAs">Reference to list of QuestionnaireAnswers</param>
		/// <param name="cachePolicy">prevalent cachepolicy</param>
		/// <param name="connectionString">database connection string.</param>
		/// <returns>A collection of QuestionnaireAnswer objects</returns>
		public ArrayList GetCompleteQuestionnaireAnswerList ( ArrayList protocolVersionQAs, ICachePolicy cachePolicy, 
			string connectionString, string moduleName )
		{
			try
			{
				DataSet questionnaireAnswersDataSet = Utility.DataAccess.GetDataSet( connectionString,
					"GetCompleteQuestionnaireAnswerList",
					Utility.DataAccess.BuildSqlParameterArray
					("@protocolVersionId", SqlDbType.Int, Id
					, "@moduleName", SqlDbType.VarChar, moduleName));

				if (questionnaireAnswersDataSet.Tables.Count > 0)
				{
					DataTable table = questionnaireAnswersDataSet.Tables[0];
					for( int i=0, count=table.Rows.Count; i < count ; ++i)
					{
						// We need to iterate over the existing QAs and make sure it wasn't 
						// already added to the Protocol Version's QAs.  When the PV gets cloned,
						// a new QA for each existing QA gets created (with Id and ProtocolVersion = 0)
						// but they haven't necessarily been persisted to the DB yet so getting the complete
						// list out of the DB may include them
						QuestionnaireAnswer answer = new QuestionnaireAnswer(cachePolicy, table.Rows[i]);
						bool exists = false;
						foreach (QuestionnaireAnswer existingAnswer in protocolVersionQAs)
						{
							if ((existingAnswer.Id == 0) && 
								(existingAnswer.QuestionnaireVersion.Questionnaire.Name ==
								answer.QuestionnaireVersion.Questionnaire.Name))
							{
								exists = true;
								break;
							}
						}
						if (!exists)
							protocolVersionQAs.Add( new QuestionnaireAnswer(cachePolicy, table.Rows[i]) );
					}
				}
				else
				{
					throw new Exception("GetCompleteQuestionnaireAnswerList stored procedure returned incorrect results");
				}
				return protocolVersionQAs;
			}
			catch(Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog ("ProtocolVersion.GetCompleteQuestionnaireAnswerList(): Failed to get all the QuestionnaireAnswers for the Protocol Version", 
					ex, true, Utility.ExceptionReport.ReportType.Error);
				throw new Exception("ProtocolVersion.GetCompleteQuestionnaireAnswerList(): Failed to get all the QuestionnaireAnswers for the Protocol Version", ex);
			}
		}


		/// <summary>
		/// Creates a new QuestionnaireAnswer and adds it to the collection
		/// after setting some properties.
		/// </summary>
		/// <param name="questionnaireVersionId">the ID of the related QV that this 
		///	QuestionnaireAnswer relates to</param>
		/// <param name="cachePolicy">caching policy used in construction.</param>
		/// <returns>the instance of the QuestionnaireAnswer.</returns>
		public Forms.QuestionnaireAnswer AddNewQuestionnaireAnswer ( int questionnaireVersionId, ICachePolicy cachePolicy )
		{
			Forms.QuestionnaireAnswer newQA = new Forms.QuestionnaireAnswer ( cachePolicy );
			newQA.QuestionnaireVersionId = questionnaireVersionId;
			QuestionnaireAnswers.Add ( newQA );
			
			return newQA;
		}

		
		/// <summary>
		/// Creates a new QuestionnaireAnswer and adds it to the collection after setting some properties
		/// </summary>
		/// <param name="questionnaireVersionId">the ID of the related QV that this 
		///	QuestionnaireAnswer relates to</param>
		/// <param name="cachePolicy">caching policy used in construction.</param>
		/// <param name="name">name of the questionnaire answer</param>
		/// <param name="required">whether the questionnaire answer must be filled out to pass validation</param>
		/// <returns>the instance of the QuestionnaireAnswer.</returns>
		public Forms.QuestionnaireAnswer AddNewQuestionnaireAnswer ( int questionnaireVersionId, 
			ICachePolicy cachePolicy, string name, bool required )
		{
			Forms.QuestionnaireAnswer newQA = new Forms.QuestionnaireAnswer ( cachePolicy );
			newQA.QuestionnaireVersionId = questionnaireVersionId;
			newQA.Name = name;
			newQA.Required = required;
            if ( !QuestionnaireAnswers.Contains( newQA ) )
    			QuestionnaireAnswers.Add ( newQA );
			
			return newQA;
		}


		/// <summary>
		/// Gets the Questionnaire Answers for a protocol Version
		/// </summary>//No more required(as the properties get the documents for the version )
		/// <param name="cachePolicy"></param>
		/// <returns></returns>
		public ArrayList GetQuestionnaireAnswers(ICachePolicy cachePolicy)
		{
			ArrayList questionnaireAnswersList ;

			DataSet questionnaireAnswersDataSet = Utility.DataAccess.GetDataSet( Utility.DataAccess.ConnectionString,
				"GetProtocolVersionQuestionnaireAnswers",Utility.DataAccess.BuildSqlParameterArray
				("@protocolVersionId", SqlDbType.Int, Id
                 ,"@printTypeKey", SqlDbType.VarChar, PrintTypeKey
                ));

			DataTable table = questionnaireAnswersDataSet.Tables[0];
			int count =table.Rows.Count;
			questionnaireAnswersList = new ArrayList();
			for( int i=0; i < count ; ++i)
			{
				DataRow row = table.Rows[i];
				Forms.QuestionnaireAnswer questionnaireAnswers=new Forms.QuestionnaireAnswer(cachePolicy,row);
				questionnaireAnswersList.Add( questionnaireAnswers );
				
			}
			return questionnaireAnswersList;
		}


		/// <summary>
		///  method to load all Answers for a given Questionnaire Answer Id.
		/// </summary>
		/// <param name="questionnaireAnswerId">ID of the QuestionnaireVersion to load the 
		/// answers for.</param>
		/// <returns>Returns the loaded ArrayList, or NULL if none exist.</returns>
		public  ArrayList GetAnswers ( int questionnaireAnswerId )
		{
			ArrayList answers = new ArrayList();

			DataSet answersDataSet = Utility.DataAccess.GetDataSet( Utility.DataAccess.ConnectionString,
				"GetQuestionnaireAnswerAnswers",
				Utility.DataAccess.BuildSqlParameterArray
				("@questionnaireAnswerId", SqlDbType.Int, questionnaireAnswerId));

			// create a new Answer for each.
			DataTable table = answersDataSet.Tables[0];
			int answerCount=table.Rows.Count;
			for( int i=0; i < answerCount; ++i)
			{
				DataRow row = table.Rows[i];
				Forms.Answer answer = new Forms.Answer( CachePolicy, row );
				answers.Add( answer );
			}

			return answers;
		}

		/// <summary>
		/// Checks whether the ProtocolVersion currently has associated with it
		/// a questionnaireAnswer with the given name 
		/// </summary>
		/// <param name="questionnaireAnswerName">name to check</param>
		/// <returns>true if the QuestionnaireAnswer has already been created</returns>
		public bool CheckQuestionnaireAnswerExistence(string questionnaireAnswerName)
		{
			foreach (FormsManagement.QuestionnaireAnswer answer in QuestionnaireAnswers)
			{
				if (answer.Name == questionnaireAnswerName)
					return true;
			}
			return false;
		}

		/// <summary>
		/// Deletes all questionnaireAnswers for this protocolversion associated with the 
		/// a questionnaire that has the given name
		/// </summary>
		/// <param name="questionnaireName">name to match on for deletion</param>
		public void DeleteQuestionnaireAnswer(string questionnaireName)
		{
			ArrayList answers = QuestionnaireAnswers;
			for ( int index = answers.Count-1; index >= 0; --index)
			{
				FormsManagement.QuestionnaireAnswer questionnaireAnswer = 
					(FormsManagement.QuestionnaireAnswer)answers[index];

				if( questionnaireAnswer.QuestionnaireVersion.Questionnaire.Name == questionnaireName )
				{
					DeleteQuestionnaireAnswer(questionnaireAnswer.Id);
					QuestionnaireAnswers.RemoveAt(index);
				}
			}
		}

		/// <summary>
		/// Removes the Questionnaire Answer and the mapping record
		/// </summary>
		/// <param name="questionnaireAnswerId">Id of the Questionnaire Answer to be removed</param>
		public void DeleteQuestionnaireAnswer(int questionnaireAnswerId)
		{
			SqlConnection connection = null;
			SqlTransaction transaction = null;
			try
			{
				connection = new SqlConnection(Utility.DataAccess.ConnectionString);

				// create a connection and open it.
				connection.Open();

				// create a transaction on the connection to be passed around.
				transaction = connection.BeginTransaction( Assembly.GetExecutingAssembly().GetName().Name);

				Utility.DataAccess.ExecuteNonQuery( transaction.Connection, transaction, "DeleteProtocolVersionQuestionnaireAnswerMap",Utility.DataAccess.BuildSqlParameterArray(
					"@protocolVersionId", SqlDbType.Int, Id,  
					"@questionnaireAnswerId", SqlDbType.Int, questionnaireAnswerId));

				Utility.DataAccess.ExecuteNonQuery( transaction.Connection, transaction, "DeleteQuestionnaireAnswer",Utility.DataAccess.BuildSqlParameterArray(
					"@id", SqlDbType.Int, questionnaireAnswerId));

				transaction.Commit();

			}
			catch (Exception e)
			{
				if (transaction != null)
					transaction.Rollback();
				Utility.ExceptionReport.WriteToEventLog ("Failed to remove log Item, error occurred at RemovelogItems()", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
			finally
			{
				if (connection != null && connection.State != ConnectionState.Closed)
					connection.Close();
			}
		}
		
		
		/// <summary>
		/// Creates a questionnaireAnswer based on the passed in questionnaireAnswerName.  If this questionnaireAnswer
		/// already exists in this ProtocolVersion (which would be the case if the Amendment script is running for the 
		/// second time and a checkbox was checked both times), nothing happens.  If it doesn't exist, and there isn't
		/// a corresponding questionnaireAnswer in the latest version of the application, a new blank questionnaire
		/// answer is created.  If there WAS a questionnaireAnswer in the latest version of the application with the 
		/// same questionnaireAnswerName, and there does not exist a matching questionnaireAnswer in this Protocol Version, 
		/// the questionnaireAnswer is copied over into a new questionnaireAnswer for this Protocol Version.
		/// 
		/// </summary>
		/// <param name="questionnaireAnswerName"></param>
		/// <param name="questionnaireName"></param>
		/// <param name="isMultiple">indicates whether there can be multiple questionnaire answers for this
		/// particular questionnaire (currently this is children, drugs, devices, sponsors)</param>
		public void CreateNewQuestionnaireAnswer(string connectionString, string questionnaireAnswerName, string questionnaireName, 
			ArrayList oldAnswers, bool isMultiple, int protocolId)
		{
            string questionnaireType = FormsManagement.Constants.QuestionnaireType.Forms;
            Protocol protocol = new Protocol( CachePolicy );
            protocol.Load(connectionString, protocolId);
            if (protocol.ModuleType == Constants.ModuleType.Animals)
                questionnaireType = FormsManagement.Constants.QuestionnaireType.Animals;

            FormsManagement.QuestionnaireVersion currentQuestionnaireVersion =
				FormsManagement.Questionnaire.GetActiveVersion(CachePolicy, questionnaireName, questionnaireType);	

			ProtocolVersion latestInitialReview = 
				Protocol.GetLatestApplicationVersion(protocolId, connectionString, false, CachePolicy);

			if (isMultiple)
				HandleMultiples(currentQuestionnaireVersion, latestInitialReview, oldAnswers, questionnaireAnswerName, questionnaireName, questionnaireType);
			else
			{
				if ((oldAnswers == null) && !CheckQuestionnaireAnswerExistence(questionnaireAnswerName))
					CreateFirstQuestionnaireAnswer(questionnaireAnswerName, questionnaireName, questionnaireType);
				else 
				{
					Forms.QuestionnaireAnswer oldQuestionnaireAnswer = null;
					foreach (Forms.QuestionnaireAnswer questionnaireAnswer in oldAnswers)
						// get old answer to this questionnaire if it exists (for cloning)
						if (questionnaireAnswer.Name == questionnaireAnswerName)
						{
							oldQuestionnaireAnswer = questionnaireAnswer;
							break;
						}

					if ((oldQuestionnaireAnswer == null) && !CheckQuestionnaireAnswerExistence(questionnaireAnswerName))
						CreateFirstQuestionnaireAnswer(questionnaireAnswerName, questionnaireName, questionnaireType);

					else if (!CheckQuestionnaireAnswerExistence(questionnaireAnswerName))
					{	// make sure that during the current version, this questionnaire has never been created
						// (in which case it has already been cloned)
						Forms.QuestionnaireAnswer newQuestionnaireAnswer = oldQuestionnaireAnswer.Clone(false);
						newQuestionnaireAnswer.QuestionnaireVersionId = currentQuestionnaireVersion.Id;
						QuestionnaireAnswers.Add(newQuestionnaireAnswer);
					}
				}
			}
		}

		//		/// <summary>
//		/// Determines the number of forms (for a multiple) that are currently tied to this protocol
//		/// version
//		/// </summary>
//		/// <param name="questionnaireName"></param>
//		/// <returns></returns>
//		public int GetCurrentFormCountByName(string questionnaireName)
//		{
//			QuestionnaireVersion currentQuestionnaireVersion = 
//				Questionnaire.GetActiveVersion(CachePolicy, questionnaireName,FormsManagement.Constants.QuestionnaireType.Forms);
//
//			int numberCurrentForms = 0;
//			foreach (QuestionnaireAnswer amendmentQuestionnaireAnswer in QuestionnaireAnswers)
//			{
//				if (amendmentQuestionnaireAnswer.QuestionnaireVersion.Questionnaire.Name ==
//					questionnaireName)
//					++numberCurrentForms;
//			}
//
//			return numberCurrentForms;
//		}

		/// <summary>
		/// For a form that allows multiples, this method checks whether the form was previously filled out
		/// in the Application.
		/// If so, it clones it and adds the new questionnaireAnswer to the ProtocolVersion (as long as it 
		/// doesn't already exist -- which it could if the amendment script has already run and the user is
		/// modifying the amendment form)
		/// 
		/// If no old form exists, set the "Show" attribute on the protocol version so the overview page 
		/// (forms tab) knows to show the form and provide a link
		/// </summary>
		/// <param name="currentQuestionnaireVersion">the most up-to-date version of this questionnaire</param>
		/// <param name="latestInitialReview">most up-to-date version of the application</param>
		/// <param name="oldAnswers">questionnaire answers tied to the latest initial review</param></param>
		/// <param name="questionnaireAnswerName">used when creating the first QA of a questionnaire</param>
		/// <param name="questionnaireName">name to identify the questionnaire by</param>
		private void HandleMultiples(Forms.QuestionnaireVersion	currentQuestionnaireVersion, 
			ProtocolVersion latestInitialReview, ArrayList oldAnswers, string questionnaireAnswerName,
			string questionnaireName, string questionnaireType)
		{
			bool foundOld = false;
			bool newExists;
			ArrayList newAnswers = QuestionnaireAnswers;

			// go through QAs in the latest version of the application to see if this QA was
			// answered (for cloning purposes)
			foreach(QuestionnaireAnswer questionnaireAnswer in oldAnswers)
			{
				newExists = false;
				if (questionnaireAnswer.QuestionnaireVersion.Questionnaire.Name == questionnaireName)
				{
					foundOld = true;
					// we found an original version of the QA; now see if we've already cloned it and
					// added it to the current version
					foreach (QuestionnaireAnswer newAnswer in newAnswers)
						// we must use the answername b/c to ensure the correct clone
						if (newAnswer.Name == questionnaireAnswer.Name) 
						{
							newExists = true;
							break;
						}

					// we don't have a cloned version of the original; create one for this version
					if (!newExists)
					{
						QuestionnaireAnswer newQuestionnaireAnswer = questionnaireAnswer.Clone(false);
						newQuestionnaireAnswer.Name = questionnaireAnswer.Name;
						newQuestionnaireAnswer.QuestionnaireVersionId = currentQuestionnaireVersion.Id;
						QuestionnaireAnswers.Add(newQuestionnaireAnswer);	
						newExists = true;
					}
				}
			}
			if (!foundOld)
			{
				newExists = false;
				// check if we've already added a new QA
				foreach (QuestionnaireAnswer newAnswer in newAnswers)
				{
					// we can't use the answername b/c it may be different if the user has
					// begun the form
					if (newAnswer.QuestionnaireVersion.Questionnaire.Name == questionnaireName) 
					{
						newExists = true;
						break;
					}
				}
				if (!newExists)
					CreateFirstQuestionnaireAnswer(questionnaireAnswerName, questionnaireName, questionnaireType);

			}
		}

		/// <summary>
		/// Creates the first version of a questionnaireAnswer (no cloning old answers)
		/// </summary>
		/// <param name="questionnaireAnswerName">name of the questionnaireanswer</param>
		/// <param name="questionnaireName">name of the question</param>
		private void CreateFirstQuestionnaireAnswer(string questionnaireAnswerName, string questionnaireName,
                                                    string questionnaireType)
		{
            FormsManagement.QuestionnaireVersion latest = 
				FormsManagement.Questionnaire.GetActiveVersion(CachePolicy, questionnaireName, questionnaireType);	
			AddNewQuestionnaireAnswer(latest.Id, CachePolicy, questionnaireAnswerName, false);
		}

        		/// <summary>
		/// Serialize the application Items(Form Collections) in to XML as string Output
		/// </summary>
		/// <param name="cachePolicy">Takes in CachePolicy as the Param</param>			
		/// <param name="logoPath">Insight logo Path</param>																															
      /// <param name="protocolProcess">the associated protocol process to be serialized</param>																															
      /// <returns>returns the serialized forms collection as a string to the caller</returns>
        public string Serialize(ICachePolicy cachePolicy, string logoPath,
            ArrayList staff, ArrayList protolDocuments, string pntTypeKey)
        {
            PrintTypeKey = pntTypeKey;
            return Serialize(cachePolicy, logoPath, staff, protolDocuments);
        }

		/// <summary>
		/// Serialize the application Items(Form Collections) in to XML as string Output
		/// </summary>
		/// <param name="cachePolicy">Takes in CachePolicy as the Param</param>			
		/// <param name="logoPath">Insight logo Path</param>																															
      /// <param name="protocolProcess">the associated protocol process to be serialized</param>																															
      /// <returns>returns the serialized forms collection as a string to the caller</returns>
		public string Serialize(ICachePolicy cachePolicy, string logoPath,
			ArrayList staff, ArrayList protolDocuments )
		{
			string connection=Utility.DataAccess.GetConnectionString();

			if (protocolProcessId !=0 )
			{
				DataTable dt=Utility.DataAccess.GetDataTable( connection,
					"GetPDFHeaderDetails",
					Utility.DataAccess.BuildSqlParameterArray(
					"@protocolProcessId", SqlDbType.Int, protocolProcessId));
				DataRow dr=dt.Rows[0];
				Forms.Serialization.Forms forms = new PHSRAG.Insight21.FormsManagement.Serialization.Forms();
				forms.Title=(DBNull.Value==dr["Title"])? string.Empty:dr["Title"].ToString();
				forms.PIName=(DBNull.Value==dr["PIName"])?string.Empty:dr["PIName"].ToString();
				forms.ProtocolNo=(DBNull.Value==dr["ProtocolNo"])?string.Empty:dr["ProtocolNo"].ToString();
				forms.Sponsor=(DBNull.Value==dr["Sponsor"])?string.Empty:dr["Sponsor"].ToString();
				forms.ApprovedDate = (DBNull.Value == dr["ApprovedDate"]) ? string.Empty : ((DateTime)dr["ApprovedDate"]).ToString("MMMM dd, yyyy");
				forms.ExpiryDate = (DBNull.Value == dr["ExpiryDate"]) ? string.Empty : ((DateTime)dr["ExpiryDate"]).ToString("MMMM dd, yyyy");
				forms.Today = (DBNull.Value == dr["Today"]) ? string.Empty : ((DateTime)dr["Today"]).ToString("MMMM dd, yyyy");
				forms.LogoLocation=	logoPath;
				forms.Type = (DBNull.Value == dr["Type"]) ? string.Empty : dr["Type"].ToString();
                forms.Species = (DBNull.Value == dr["SpeciesCode"]) ? string.Empty : dr["SpeciesCode"].ToString();
                
				if (DBNull.Value != dr["FormsID"])
				{
					string formsId;
					formsId = forms.FormsId = dr["FormsID"].ToString();
					int processNumber = 0;
					if (formsId.Length > 0)
					{
						//No permanent number from Rex, include the whole forms id
						if (formsId.IndexOf('-') > 0)
							forms.Type = string.Format("{0} {1}", forms.Type, formsId);
						else
						{
							int.TryParse(Regex.Replace(formsId, "[A-Za-z]+", ""), out processNumber);
							if (processNumber != 0)
								forms.Type = string.Format("{0} {1}", forms.Type, processNumber.ToString());
						}
					}
				}

				forms.IsInterventionStudy = (DBNull.Value == dr["IsInterventionStudy"]) ? false : Convert.ToBoolean(dr["IsInterventionStudy"]);
				forms.Signatures = GetSignatures(connection);
				
                if (dt.Columns.Contains("ModuleType"))
                    forms.ModuleType = (DBNull.Value == dr["ModuleType"]) ? string.Empty : dr["ModuleType"].ToString();

				if (null != staff  &&  staff.Count > 0)
				{
					forms.StudyStaff = new ArrayList();
					foreach(StaffPerson staffPerson in staff)
					{
						Forms.Serialization.FormStudyPerson formStudyPerson = new PHSRAG.Insight21.FormsManagement.Serialization.FormStudyPerson();
						formStudyPerson.Name = string.Format("{0}, {1}",staffPerson.LastName, staffPerson.Person.FirstName);
						formStudyPerson.Role = staffPerson.Role;
						formStudyPerson.Degrees = staffPerson.Person.DegreeList;
						formStudyPerson.Organization = Organization.StripDomain(staffPerson.OrganizationName);
						forms.StudyStaff.Add(formStudyPerson);
					}
				}

				if (null != protolDocuments  &&  protolDocuments.Count > 0)
				{
					forms.Attachments = new ArrayList();
					foreach(ProtocolDocument protocolDocument in protolDocuments)
					{
						Forms.Serialization.FormAttachment formAttachment = new PHSRAG.Insight21.FormsManagement.Serialization.FormAttachment();
						formAttachment.Name = protocolDocument.Name;
						formAttachment.Type = protocolDocument.RefMeaning;

						if ( protocolDocument.IsHardCopy )
						{
							formAttachment.Mode = "Hardcopy";
						}
						else if ( protocolDocument.IsElectronicFile )
						{
							formAttachment.Mode = "Electronic";
						}

						forms.Attachments.Add(formAttachment);
					}
				}

				ArrayList questionnaireAnswersForProtocol=GetQuestionnaireAnswers(cachePolicy);
				Utility.NameObjectCollection organizedForms = new PHSRAG.Utility.NameObjectCollection();
				string sponsorName = string.Empty;

				foreach (Forms.QuestionnaireAnswer qA in questionnaireAnswersForProtocol)
				{
					// Don't include the QA in the output if there is no change to the form
					// (if it's amendment and this form isn't being amended) OR if the user 
					// hasn't filled out the form yet
					if ( ((int)QuestionnaireAnswer.UserAction.NoChange == qA.Action) ||
						(qA.Name == Forms.Constants.QuestionnaireAnswerDefaultNames.Sponsor_IR) ||
						(qA.Name == Forms.Constants.QuestionnaireAnswerDefaultNames.Sponsor_AM) ||
						(qA.Name == Forms.Constants.QuestionnaireAnswerDefaultNames.Drugs) ||
						(qA.Name == Forms.Constants.QuestionnaireAnswerDefaultNames.MedicalDevices) ||
						(qA.Name == Forms.Constants.QuestionnaireAnswerDefaultNames.Children))
					{
						continue;
					}
			   
					Forms.QuestionnaireVersion questionnaireVersion = new Forms.QuestionnaireVersion(cachePolicy);
					questionnaireVersion.Load(connection,(qA.QuestionnaireVersionId));

					Forms.Questionnaire questionnaire = new Forms.Questionnaire(cachePolicy);
					questionnaire.Load(connection,questionnaireVersion.QuestionnaireID);

					if (questionnaire.Category != Forms.Constants.InitialApplicationCategory.InitialQuestionnaire)
					{
						Serialization.Form form = questionnaireVersion.GetForm(qA);
						ArrayList formList = organizedForms[qA.QuestionnaireVersion.Questionnaire.Name] as ArrayList;
						if (formList == null)
							organizedForms[qA.QuestionnaireVersion.Questionnaire.Name] = formList = new ArrayList();
						formList.Add(form);
						if (qA.QuestionnaireCategory == Forms.Constants.CommonFormCategory.SponsorFunding)
							sponsorName = qA.QuestionnaireVersion.Questionnaire.Name;
					}
				}
				// sponsor set not guaranteed to exist (e.g. an amendment where not changing
				// sponsor)
				if (sponsorName != string.Empty)
				{
					forms.FormCollection.AddRange((ArrayList)organizedForms[sponsorName]);
					organizedForms.Remove(sponsorName);
				}
				foreach (string key in organizedForms.Keys)
					forms.FormCollection.AddRange((ArrayList)organizedForms[key]);

				return Serialization.QuestionnaireSerializer.Serialize(forms);
			}
			return null;
		}


		/// <summary>
		/// Returns an Arraylist of QuestionnaireAnswers that correspond to the specified Version
		/// </summary>
		/// <param name="questionnaireVersionId">Id of the questionnaire version</param>
		/// <returns>Collection of QuestionanireAnswers</returns>
		public ArrayList GetAllQVQAs(int questionnaireVersionId)
		{
			ArrayList al = new ArrayList();
			foreach (QuestionnaireAnswer qa in QuestionnaireAnswers)
			{
				if (qa.QuestionnaireVersionId == questionnaireVersionId)
					al.Add(qa);
			}
			return al;
		}

		public ArrayList GetQuestionnaireAnswers(string questionnaireCategory)
		{
			ArrayList qAs = new ArrayList();
			foreach (QuestionnaireAnswer qa in QuestionnaireAnswers)
			{
				if (qa.QuestionnaireCategory == questionnaireCategory)
					qAs.Add(qa);
			}
			return qAs;
		}
		#endregion

		#region Caching
		/// <summary>
		/// Cache this instance using the prevalent cache policy.
		/// </summary>
		public override void Cache()
		{
			CachePolicy.Cache(ProtocolVersionKey, this);
		}

		/// <summary>
		/// Remove this instance from the cache using the prevalent cache policy.
		/// </summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(ProtocolVersionKey);
		}
		#endregion

		#region Static Methods 
		/// <summary>
		/// Static method to load all ProtocolVersions for a given
		/// ProtocolProcess.
		/// </summary>
		/// <param name="protocolProcessId">ID of the Process to load the 
		/// versions for.</param>
		/// <returns>Returns the loaded ArrayList, or NULL if none exist.</returns>
		public static ArrayList GetVersions ( int protocolProcessId, ICachePolicy cachePolicy )
		{
			ArrayList versions = new ArrayList();

			DataSet versionsDataSet = Utility.DataAccess.GetDataSet( Utility.DataAccess.ConnectionString,
										"GetProtocolVersions",
										Utility.DataAccess.BuildSqlParameterArray
										("@protocolProcessId", SqlDbType.Int, protocolProcessId));

			// create a new Version for each.
			DataTable table = versionsDataSet.Tables[0];
			int versionCount=table.Rows.Count;
			for( int i=0; i < versionCount; ++i)
			{
				DataRow row = table.Rows[i];
				ProtocolVersion version = new ProtocolVersion( cachePolicy, row );
				versions.Add( version );
			}
			return versions;
		}
		/// <summary>
		/// Deep copy of the ProtocolVersion
		/// </summary>
		/// <returns>new Protocol version cloned</returns>
		public ProtocolVersion Clone()
		{
			
			ProtocolVersion clonedProtocolVersion= new ProtocolVersion(CachePolicy);
			try
			{
				clonedProtocolVersion.Id=0;
                clonedProtocolVersion.IsClone = true;
				clonedProtocolVersion.version=version+1;
				clonedProtocolVersion.createDate=DateTime.Today;
				clonedProtocolVersion.status = status;
				clonedProtocolVersion.ProtocolProcessId = protocolProcessId;
				
				ArrayList list=QuestionnaireAnswers;
				foreach(Forms.QuestionnaireAnswer qA in list)
				{
					clonedProtocolVersion.QuestionnaireAnswers.Add(qA.Clone(false));
				}
			}
			catch(Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog ("Failed to get the cloned protocol version, error occurred at GetLatestProtocolVersionClone()", ex, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
			return clonedProtocolVersion;
		}

		#endregion

		#region Private methods
		private ArrayList GetSignatures(string connectionString)
		{
			ArrayList signaturesList = new ArrayList();
			DataTable dt = Utility.DataAccess.GetDataTable(connectionString,
					"GetSignatures",
					Utility.DataAccess.BuildSqlParameterArray(
					"@protocolProcessId", SqlDbType.Int, protocolProcessId));

			if (dt != null && dt.Rows != null)
			{
				foreach (DataRow dr in dt.Rows)
					signaturesList.Add(new FormsManagement.Serialization.FormSignature(dr));
			}
			return signaturesList;
		}
		#endregion

		#region IClonable Members
		object ICloneable.Clone()
		{
			return Clone();
		}
		#endregion

        private string printTypeKey;

        /// <summary>
        /// Get/Set the Print Type Key of the ProtocolVersion
        /// </summary>
        public String PrintTypeKey
        {
            get
            {
                return printTypeKey;
            }
            set
            {
                printTypeKey = value;
            }
        }
	}
}
